"""Domain models for WMS3D system.

This module contains the core domain models for the WMS3D system,
focusing on objects and events with their related entities.
"""

from dataclasses import dataclass
from datetime import datetime
from enum import Enum
from typing import Any, Dict, List, Optional, Set
from uuid import UUID

from geoalchemy2 import Geometry
from pydantic import BaseModel, Field
from sqlalchemy import JSON, Boolean, Column, DateTime, Numeric, String, Text
from sqlalchemy.dialects.postgresql import UUID as UUIDType
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class StateTransitionError(Exception):
    """状态转换异常"""

    def __init__(self, current: str, target: str, reason: str):
        self.current = current
        self.target = target
        self.reason = reason
        super().__init__(f"Cannot transition from {current} to {target}: {reason}")


class ObjectStatus(str, Enum):
    """物品状态枚举。

    定义物品在仓库管理系统中的各种状态。
    按业务领域分组：入库流程、在库操作、出库流程、系统状态。

    入库流程：从到货到上架的完整流程
    在库操作：已上架物品的各种操作（盘点、调拨、质检）
    出库流程：从下单到发货的完整流程
    系统状态：系统管理和异常状态
    """

    # 入库流程状态
    PENDING = "pending"  # 待处理（初始状态）
    ARRIVED = "arrived"  # 已到货
    UNLOADED = "unloaded"  # 已卸货
    SORTING_TASK_GENERATED = "sorting_task_generated"  # 生成分拣任务
    SORTED = "sorted"  # 已分拣
    PUTAWAY_TASK_GENERATED = "putaway_task_generated"  # 生成上架任务
    STORED = "stored"  # 已上架

    # 在库操作状态 - 核心状态，支持并行操作
    IN_STOCK = "in_stock"  # 在库（核心状态，可发起多种操作）

    # 盘点相关状态
    INVENTORY_IN_PROGRESS = "inventory_in_progress"  # 盘点中
    INVENTORY_COMPLETED = "inventory_completed"  # 盘点完成

    # 调拨相关状态
    TRANSFER_IN_PROGRESS = "transfer_in_progress"  # 调拨中
    TRANSFER_COMPLETED = "transfer_completed"  # 调拨完成

    # 质检相关状态
    QC_IN_PROGRESS = "qc_in_progress"  # 质检中
    QC_COMPLETED = "qc_completed"  # 质检完成
    DAMAGED = "damaged"  # 破损（质检异常结果）

    # 出库流程状态
    ORDERED = "ordered"  # 已被下单
    PICKING_TASK_GENERATED = "picking_task_generated"  # 已生成拣货单
    PICKING_COMPLETED = "picking_completed"  # 确认拣货完成
    SHIPPED = "shipped"  # 已装车发货

    # 运输和预留状态
    IN_TRANSIT = "in_transit"  # 运输中
    RESERVED = "reserved"  # 已预留
    PICKED = "picked"  # 已拣选（保留兼容性）

    # 系统管理状态
    ARCHIVED = "archived"  # 已归档
    DELETED = "deleted"  # 已删除
    OBJECT_CREATED = "object_created"  # 物品已创建（用于批量更新）


# 常量定义
class Constants:
    COORDINATE_SRID = 4326
    EVENT_TYPE_CREATED = "object_created"
    EVENT_TYPE_DELETED = "object_deleted"
    EVENT_TYPE_UPDATED = "object_updated"
    DOCUMENT_TYPE_BATCH = "batch_operation"
    DOCUMENT_STATUS_ACTIVE = "active"
    SYSTEM_USER = "system"
    DEFAULT_VERSION = "1.0"


@dataclass
class OperationContext:
    """操作上下文数据传输对象"""

    documentdata: "DocumentDataRequest"
    sensorsource: "SensorSource"
    sku_ids: List[str] | None
    db: "AsyncSession"
    openid: UUID | None = None
    logger: Any = None


@dataclass
class OperationResult:
    """操作结果数据传输对象"""

    objects_updated: list["Object"]
    objects_created: list["Object"]
    objects_deleted: list[str]
    events_created: list["Event"]


@dataclass
class ObjectCoordinates:
    """对象坐标数据传输对象"""

    object_id: UUID
    coordinates: list[float]


class ObjectLifeCycle:
    """物品生命周期状态机。

    基于业务逻辑的状态转换规则，支持并行操作分支。
    按业务领域组织状态转换，消除线性限制。
    """

    # 状态转换规则 - 基于业务逻辑定义
    TRANSITIONS = {
        # 入库流程
        ObjectStatus.OBJECT_CREATED.value: [ObjectStatus.ARRIVED.value],
        ObjectStatus.ARRIVED.value: [ObjectStatus.UNLOADED.value],
        ObjectStatus.UNLOADED.value: [ObjectStatus.SORTING_TASK_GENERATED.value],
        ObjectStatus.SORTING_TASK_GENERATED.value: [
            ObjectStatus.SORTED.value,
            ObjectStatus.QC_IN_PROGRESS.value,
            ObjectStatus.DELETED.value,
        ],
        ObjectStatus.SORTED.value: [
            ObjectStatus.PUTAWAY_TASK_GENERATED.value,
            ObjectStatus.QC_IN_PROGRESS.value,
        ],
        ObjectStatus.PUTAWAY_TASK_GENERATED.value: [ObjectStatus.STORED.value],
        ObjectStatus.STORED.value: [ObjectStatus.IN_STOCK.value],
        # 在库操作 - 从IN_STOCK可以发起多种并行操作
        ObjectStatus.IN_STOCK.value: [
            ObjectStatus.INVENTORY_IN_PROGRESS.value,
            ObjectStatus.TRANSFER_IN_PROGRESS.value,
            ObjectStatus.QC_IN_PROGRESS.value,
            ObjectStatus.ORDERED.value,
        ],
        # 盘点流程
        ObjectStatus.INVENTORY_IN_PROGRESS.value: [ObjectStatus.INVENTORY_COMPLETED.value],
        ObjectStatus.INVENTORY_COMPLETED.value: [ObjectStatus.IN_STOCK.value],
        # 调拨流程
        ObjectStatus.TRANSFER_IN_PROGRESS.value: [ObjectStatus.TRANSFER_COMPLETED.value],
        ObjectStatus.TRANSFER_COMPLETED.value: [ObjectStatus.IN_STOCK.value],
        # 质检流程 - 支持正常和异常结果
        ObjectStatus.QC_IN_PROGRESS.value: [
            ObjectStatus.QC_COMPLETED.value,
            ObjectStatus.DAMAGED.value,
        ],
        ObjectStatus.QC_COMPLETED.value: [
            ObjectStatus.IN_STOCK.value,
            ObjectStatus.SORTED.value,
            ObjectStatus.PUTAWAY_TASK_GENERATED.value,
            ObjectStatus.SORTING_TASK_GENERATED.value,
        ],
        ObjectStatus.DAMAGED.value: [ObjectStatus.ARCHIVED.value],
        # 出库流程
        ObjectStatus.ORDERED.value: [ObjectStatus.PICKING_TASK_GENERATED.value],
        ObjectStatus.PICKING_TASK_GENERATED.value: [ObjectStatus.PICKING_COMPLETED.value],
        ObjectStatus.PICKING_COMPLETED.value: [ObjectStatus.SHIPPED.value],
        ObjectStatus.SHIPPED.value: [ObjectStatus.ARCHIVED.value],
        # 其他状态转换
        ObjectStatus.IN_TRANSIT.value: [ObjectStatus.ARRIVED.value, ObjectStatus.STORED.value],
        ObjectStatus.RESERVED.value: [ObjectStatus.IN_STOCK.value, ObjectStatus.PICKED.value],
        ObjectStatus.PICKED.value: [ObjectStatus.SHIPPED.value, ObjectStatus.IN_TRANSIT.value],
        # 系统状态转换
        ObjectStatus.ARCHIVED.value: [ObjectStatus.DELETED.value],
    }

    # 向后兼容 - 保留原有线性顺序
    ORDER: list[str] = [
        ObjectStatus.OBJECT_CREATED.value,
        ObjectStatus.ARRIVED.value,
        ObjectStatus.UNLOADED.value,
        ObjectStatus.SORTING_TASK_GENERATED.value,
        ObjectStatus.SORTED.value,
        ObjectStatus.PUTAWAY_TASK_GENERATED.value,
        ObjectStatus.STORED.value,
        ObjectStatus.IN_STOCK.value,
    ]

    @classmethod
    def is_valid_transition(cls, current: str, target: str) -> bool:
        """检查状态转换是否合法。

        Args:
            current: 当前状态
            target: 目标状态

        Returns:
            bool: 转换是否合法
        """
        # 向后兼容性检查
        if current in cls.TRANSITIONS:
            return target in cls.TRANSITIONS[current]

        # 如果当前状态不在转换规则中，尝试使用旧的线性逻辑
        return cls.next_status(current, target)

    @classmethod
    def get_valid_next_states(cls, current: str) -> list[str]:
        """获取当前状态的所有合法下一个状态。

        Args:
            current: 当前状态

        Returns:
            List[str]: 合法的下一个状态列表
        """
        return cls.TRANSITIONS.get(current, [])

    @classmethod
    def get_status_category(cls, status: str) -> str:
        """获取状态所属的业务领域。

        Args:
            status: 状态值

        Returns:
            str: 业务领域分类
        """
        inbound_states = [
            ObjectStatus.PENDING.value,
            ObjectStatus.ARRIVED.value,
            ObjectStatus.UNLOADED.value,
            ObjectStatus.SORTING_TASK_GENERATED.value,
            ObjectStatus.SORTED.value,
            ObjectStatus.PUTAWAY_TASK_GENERATED.value,
            ObjectStatus.STORED.value,
        ]

        inventory_states = [
            ObjectStatus.IN_STOCK.value,
            ObjectStatus.INVENTORY_IN_PROGRESS.value,
            ObjectStatus.INVENTORY_COMPLETED.value,
            ObjectStatus.TRANSFER_IN_PROGRESS.value,
            ObjectStatus.TRANSFER_COMPLETED.value,
            ObjectStatus.QC_IN_PROGRESS.value,
            ObjectStatus.QC_COMPLETED.value,
        ]

        outbound_states = [
            ObjectStatus.ORDERED.value,
            ObjectStatus.PICKING_TASK_GENERATED.value,
            ObjectStatus.PICKING_COMPLETED.value,
            ObjectStatus.SHIPPED.value,
        ]

        system_states = [
            ObjectStatus.IN_TRANSIT.value,
            ObjectStatus.RESERVED.value,
            ObjectStatus.PICKED.value,
            ObjectStatus.DAMAGED.value,
            ObjectStatus.ARCHIVED.value,
            ObjectStatus.DELETED.value,
            ObjectStatus.OBJECT_CREATED.value,
        ]

        if status in inbound_states:
            return "inbound"
        elif status in inventory_states:
            return "inventory"
        elif status in outbound_states:
            return "outbound"
        elif status in system_states:
            return "system"
        else:
            return "unknown"

    @classmethod
    def can_initiate_parallel_operations(cls, status: str) -> bool:
        """检查状态是否可以发起并行操作。

        Args:
            status: 当前状态

        Returns:
            bool: 是否可以发起并行操作
        """
        return status == ObjectStatus.IN_STOCK.value

    @classmethod
    def is_terminal_state(cls, status: str) -> bool:
        """检查是否为终止状态。

        Args:
            status: 状态值

        Returns:
            bool: 是否为终止状态
        """
        terminal_states = [ObjectStatus.ARCHIVED.value, ObjectStatus.DELETED.value]
        return status in terminal_states

    @classmethod
    def validate_transition(cls, current: str, target: str) -> None:
        """验证状态转换，失败时抛出异常

        Args:
            current: 当前状态
            target: 目标状态

        Raises:
            StateTransitionError: 状态转换不合法时抛出
        """
        if not cls.is_valid_transition(current, target):
            possible_states = cls.get_valid_next_states(current)
            raise StateTransitionError(
                current, target, f"转换不合法。可能的状态: {possible_states}"
            )

    @classmethod
    def get_transition_description(cls, current: str, target: str) -> str:
        """获取状态转换的业务描述

        Args:
            current: 当前状态
            target: 目标状态

        Returns:
            str: 转换的业务描述
        """
        descriptions = {
            "object_created→arrived": "物品创建完成，等待到货",
            "arrived→unloaded": "物品已到货，等待卸货",
            "unloaded→sorting_task_generated": "物品已卸货，生成分拣任务",
            "sorting_task_generated→sorted": "分拣任务执行完成",
            "sorting_task_generated→deleted": "分拣任务生成后，物品被删除",
            "sorted→putaway_task_generated": "分拣完成，生成上架任务",
            "putaway_task_generated→stored": "上架任务执行完成",
            "stored→in_stock": "物品上架完成，进入在库状态",
            "in_stock→inventory_in_progress": "发起盘点操作",
            "in_stock→transfer_in_progress": "发起调拨操作",
            "in_stock→qc_in_progress": "发起质检操作",
            "in_stock→ordered": "物品被下单，准备出库",
            "inventory_in_progress→inventory_completed": "盘点操作完成",
            "inventory_completed→in_stock": "盘点完成，返回在库状态",
            "transfer_in_progress→transfer_completed": "调拨操作完成",
            "transfer_completed→in_stock": "调拨完成，返回在库状态",
            "qc_in_progress→qc_completed": "质检通过",
            "qc_in_progress→damaged": "质检发现破损",
            "qc_completed→in_stock": "质检完成，返回在库状态",
            "qc_completed→sorted": "质检完成，返回分拣状态",
            "qc_completed→putaway_task_generated": "质检完成，继续上架流程",
            "qc_completed→sorting_task_generated": "质检完成，返回分拣任务",
            "damaged→archived": "破损物品归档",
            "ordered→picking_task_generated": "生成拣货任务",
            "picking_task_generated→picking_completed": "拣货任务完成",
            "picking_completed→shipped": "物品装车发货",
            "shipped→archived": "发货完成，物品归档",
        }

        transition_key = f"{current}→{target}"
        return descriptions.get(transition_key, "未知转换")

    @classmethod
    def get_business_flows(cls) -> dict[str, list[str]]:
        """获取支持的业务流程

        Returns:
            Dict[str, List[str]]: 业务流程字典
        """
        return {
            "inbound_flow": [
                "object_created",
                "arrived",
                "unloaded",
                "sorting_task_generated",
                "sorted",
                "putaway_task_generated",
                "stored",
                "in_stock",
            ],
            "inventory_flow": [
                "in_stock",
                "inventory_in_progress",
                "inventory_completed",
                "in_stock",
            ],
            "transfer_flow": ["in_stock", "transfer_in_progress", "transfer_completed", "in_stock"],
            "qc_flow_normal": ["in_stock", "qc_in_progress", "qc_completed", "in_stock"],
            "qc_flow_return_to_sorting": ["in_stock", "qc_in_progress", "qc_completed", "sorted"],
            "qc_flow_continue_putaway": [
                "in_stock",
                "qc_in_progress",
                "qc_completed",
                "putaway_task_generated",
            ],
            "qc_flow_abnormal": ["in_stock", "qc_in_progress", "damaged", "archived"],
            "outbound_flow": [
                "in_stock",
                "ordered",
                "picking_task_generated",
                "picking_completed",
                "shipped",
            ],
        }

    @staticmethod
    def next_status(current: str, target: str) -> bool:
        """判断 target 是否为 current 的下一个合法状态（向后兼容）。

        保留原有的线性状态转换逻辑，确保向后兼容性。
        """
        try:
            idx_cur = ObjectLifeCycle.ORDER.index(current)
            idx_tgt = ObjectLifeCycle.ORDER.index(target)
            return idx_tgt == idx_cur + 1
        except ValueError:
            return False


class DocumentDataRequest(BaseModel):
    """objects_operation 方法入参结构"""

    document_number: str
    headers: dict
    items: list[dict]
    current_status: str
    next_status: str
    document_type: str
    allow_multiple_operations: bool = False  # 默认为False（数量检查模式）
    target_position: list[float] = [0.0, 0.0, 0.0]  # 目标位置，默认为原点


class ObjectsOperationRequest(BaseModel):
    """objects_operation API 统一请求结构，包含sku_id在payload中"""

    documentdata: DocumentDataRequest
    sensorsource: "SensorSource"
    sku_ids: Optional[List[str]] = None
    openid: Optional[UUID] = None


class SensorSource(BaseModel):
    """传感器来源模型。

    表示轨迹记录的传感器来源信息。
    """

    device_type: str = Field(..., description="设备类型")
    device_id: str = Field(..., description="设备ID")
    location: str | None = Field(None, description="设备位置")
    timestamp: datetime = Field(..., description="时间戳")
    openid: UUID | None = Field(None, description="OpenID标识符")


class Position(BaseModel):
    """3D位置模型。

    表示物品在仓库中的三维坐标位置。
    """

    x: float = Field(..., description="X坐标")
    y: float = Field(..., description="Y坐标")
    z: float = Field(..., description="Z坐标")


class Location(Base):
    """库位模型。

    表示仓库中的一个库位。
    """

    __tablename__ = "locations"

    location_id: str = Column(String(50), primary_key=True, comment="库位ID")
    zone_id: str = Column(String(50), nullable=False, comment="区域ID")
    center_position: str = Column(
        Geometry(geometry_type="POINTZ", srid=4326, spatial_index=True),
        nullable=False,
        comment="中心位置",
    )
    boundary_geometry: str = Column(
        Geometry(geometry_type="POLYGONZ", srid=4326, spatial_index=True),
        nullable=False,
        comment="边界几何",
    )
    constraints: dict = Column(JSON, comment="约束条件")
    is_dynamic: bool = Column(Boolean, nullable=False, comment="是否动态库位")


class Object(Base):
    """物品模型。

    表示仓库中的一个具体物品。
    """

    __tablename__ = "objects"

    object_id: UUID = Column(UUIDType(as_uuid=True), primary_key=True, comment="物品ID")
    sku_id: str = Column(String(50), nullable=False, comment="SKU ID")
    batch_number: str | None = Column(String(50), comment="批次号")
    current_position: str = Column(
        Geometry(geometry_type="POINTZ", srid=4326, spatial_index=True),
        nullable=False,
        comment="当前位置",
    )
    status: str = Column(String(20), nullable=False, comment="状态")
    documents: dict | None = Column(JSON, comment="关联单据信息")
    openid: UUID | None = Column(
        UUIDType(as_uuid=True), comment="Open ID for warehouse item identification"
    )
    created_at: datetime = Column(
        DateTime(timezone=True), nullable=False, server_default="now()", comment="创建时间"
    )
    last_updated: datetime = Column(
        DateTime(timezone=True), nullable=False, server_default="now()", comment="最后更新时间"
    )


class Event(Base):
    """事件模型。

    表示物品或任务的事件记录，同时包含轨迹信息。
    """

    __tablename__ = "events"

    event_id: UUID = Column(UUIDType(as_uuid=True), primary_key=True, comment="事件ID")
    object_id: UUID | None = Column(UUIDType(as_uuid=True), comment="物品ID")
    task_id: UUID | None = Column(UUIDType(as_uuid=True), comment="任务ID")
    document_number: str | None = Column(String(50), comment="单据号码")
    event_type: str = Column(String(50), nullable=False, comment="事件类型")
    timestamp: datetime = Column(DateTime(timezone=True), nullable=False, comment="时间戳")
    openid: UUID | None = Column(UUIDType(as_uuid=True), comment="用户ID")
    payload: dict = Column(JSON, nullable=False, comment="事件数据")
    velocity: dict | None = Column(JSON, comment="速度信息")
    accuracy: float | None = Column(Numeric(10, 3), comment="精度")
    sensor_source: dict | None = Column(JSON, comment="传感器来源")
    object_result: str | None = Column(
        String(20), comment="物品操作结果"
    )
    sku_id: str | None = Column(
        String(100), comment="sku id"
    )
    created_at: datetime = Column(
        DateTime(timezone=True), nullable=False, server_default="now()", comment="创建时间"
    )


